package repositories;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import domain.Seed;
import domain.SeedStatus;

public class SeedRepository extends BaseRepository {

	public final int MAX_SEEDS = 25000;
	
	private static Lock lock = new ReentrantLock();

	public boolean createSeed(String seed, Seed parent) {
		boolean result = false;

		lock.lock();
		if (checkMaxSeeds() && !containsSeed(seed)) {
			Seed entity = new Seed(seed, parent);
			String sql = String.format("INSERT INTO " + 
					"  seeds " + 
					"  (Seed, Status, Depth) " + 
					"VALUES " + 
					"  ('%s', '%s', %d);",
					super.cleanString(entity.getSeed()), entity.getStatus(), entity.getDepth());

			super.executeUpdate(sql);
			result = true;
		}

		lock.unlock();

		return result;
	}

	public void saveSeed(Seed entity) throws Exception {
		if (entity.getSeedID() <= 0)
			throw new Exception("Use create seed instead.");

		String sql = String.format("UPDATE " + 
				"  seeds " + 
				"SET " + 
				"  Status = '%s', Error = '%s' " + 
				"WHERE " + 
				"  SeedID = %d", 
				entity.getStatus(),
				super.cleanString(entity.getError()), entity.getSeedID());

		super.executeUpdate(sql);
	}
	
	public boolean checkMaxSeeds() {
		boolean result = false;
		String sql = "SELECT " 
				+ "  COUNT(*) AS count " 
				+ "FROM "
				+ "	 seeds;";

		Connection conn = null;
		try {
			conn = super.getConnection();
			ResultSet results = super.executeQuery(conn, sql);

			if (results != null && results.next())
				result = results.getInt("Count") < MAX_SEEDS;
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			super.closeConnection(conn);

		}

		return result;
	}

	public boolean containsSeed(String seed) {
		// Format to match seed formatting
		seed = new Seed(seed, null).getSeed();

		boolean result = false;
		Connection conn = null;

		String sql = String.format("SELECT " + " COUNT(*) AS count " + "FROM "
				+ "	seeds " + "WHERE " + "	Seed LIKE '%s';",
				super.cleanString(seed));

		try {
			conn = super.getConnection();
			ResultSet results = super.executeQuery(conn, sql);

			if (results != null && results.next())
				result = results.getInt("Count") > 0;
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			super.closeConnection(conn);

		}

		return result;
	}

	private boolean hasSeeds(SeedStatus status, int maxDepth) {
		boolean result = false;
		Connection conn = null;

		String sql = String.format("SELECT " + 
				"  COUNT(*) AS count " + 
				"FROM " + 
				"  seeds " + 
				"WHERE " + 
				" Depth <= %d AND Status LIKE '%s';", 
				maxDepth, status);

		try {
			conn = super.getConnection();
			ResultSet results = super.executeQuery(conn, sql);

			if (results != null && results.next())
				result = results.getInt("Count") > 0;
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			super.closeConnection(conn);

		}

		return result;
	}

	private Seed getSeed(SeedStatus status, int maxDepth) {
		Seed result = null;
		Connection conn = null;

		String sql = String.format(
				"SELECT " + 
				"  SeedID, Seed, Status, Depth " + 
				"FROM " + 
				"  seeds " + 
				"WHERE " + 
				"	Depth <= %d AND Status LIKE '%s' " + 
				"ORDER BY Depth, Modified " + 
				"LIMIT 1", 
				maxDepth, status);

		try {
			conn = super.getConnection();
			ResultSet results = super.executeQuery(conn, sql);

			if (results.next()) {
				result = new Seed(
						results.getInt("SeedID"),
						results.getString("Seed"), 
						SeedStatus.valueOf(results.getString("Status")),
						results.getInt("Depth"));
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			super.closeConnection(conn);
		}

		return result;
	}
	
	public boolean hasCrawlSeeds(int maxDepth) {
		return hasSeeds(SeedStatus.Pending, maxDepth);
	}

	public Seed getCrawlSeed(int maxDepth) {
		return getSeed(SeedStatus.Pending, maxDepth);
	}
	
	public void clearSeeds() {
		super.executeUpdate("DELETE FROM seeds;");
	}
}